/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.tchepannou.limbe.interceptor;

import com.tchepannou.limbe.Context;
import com.tchepannou.limbe.Controller;
import com.tchepannou.limbe.Interceptor;
import com.tchepannou.limbe.annotation.RequireTransaction;
import com.tchepannou.limbe.service.PersistenceService;

import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This is the interceptor that start/commit/rollback transaction.
 * The interceptor will trigger the transaction if the ActionController or the
 * action method has the annotation {@link RequireTransaction}
 * 
 * @author herve
 */
public class TransactionInterceptor
    implements Interceptor
{
    //-- Static
    private static final Logger LOG = Logger.getLogger (TransactionInterceptor.class.getName ());
    
    //-- Interceptor
    @Override
    public int before (Method method, Controller controller)
    {
        begin (controller, method);
        return Interceptor.CONTINUE;
    }

    @Override
    public void after (Method method, Controller controller, Throwable e)
    {
        Context context = controller.getContext ();
        if (e == null && !context.isRollback ())
        {
            commit (controller, method);
        }
        else
        {
            rollback (controller, method, e);
        }
    }

    @Override
    public int before (Controller controller)
    {
        return Interceptor.CONTINUE;
    }

    @Override
    public void after (Controller controller)
    {
    }


    //-- Private methods
    private void begin (Controller controller, Method method)
    {
        RequireTransaction ann = getAnnotation (controller, method);
        if (ann != null)
        {
            PersistenceService ps = getPersistenceService (controller);
            if (ps != null)
            {
                ps.beginTransaction ();
            }
        }
    }

    private void commit (Controller controller, Method method)
    {
        RequireTransaction ann = getAnnotation (controller, method);
        if (ann != null)
        {
            PersistenceService ps = getPersistenceService (controller);
            if (ps != null)
            {
                ps.commitTransaction ();
            }
        }
    }

    private void rollback (Controller controller, Method method, Throwable e)
    {
        RequireTransaction ann = getAnnotation (controller, method);
        if (ann != null)
        {
            PersistenceService ps = getPersistenceService (controller);
            if (ps != null)
            {
                if (LOG.isLoggable (Level.INFO) )
                {   
                    if (e != null)
                    {
                        LOG.log (Level.SEVERE, "Rolling back transaction", e);
                    }
                    else
                    {
                        LOG.log (Level.SEVERE, "Rolling back transaction");
                    }
                }
                ps.rollbackTransaction ();
            }
        }
    }

    private RequireTransaction getAnnotation (Object controller, Method method)
    {
        RequireTransaction ann = method.getAnnotation(RequireTransaction.class);
        if (ann == null)
        {
            ann = controller.getClass ().getAnnotation (RequireTransaction.class);
        }
        return ann;
    }
    
    private PersistenceService getPersistenceService (Controller controller)
    {
        return controller.getContext ().findService (PersistenceService.class);
    }
}
